/**
  * Author: Mei
  * Date: 2020-11-22 15:32
  * Description: 
  *
  */
#include <iostream>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <thread>
#include <unistd.h>//sleep

std::mutex mut;
std::queue<int> data_queue;//-------------------①
std::condition_variable data_cond; //条件变量

void data_preparation_thread(){
    int data = 0;
    while(true){
        data++;
        std::lock_guard<std::mutex> lk(mut);
        data_queue.push(data);//-------------------②
        //唤醒线程 notify_one()后，另一个wait的线程不是马上就被唤醒！！！ 从打印结果可以看出
        data_cond.notify_one();//-------------------③
        std::cout << "after  notify_one" << std::endl;
        //std::this_thread::sleep_for(1000);
        sleep(1);
    }
}

void data_process_thread(){
    while(true){
        //这就是为什么使用std::unique_lock而不是std::lock_guard。
        // 等待中的线程必须解锁互斥元，并在wait返回true的时候重新锁定这个互斥元，std::lock_guard没有这个功能。
        // 如果线程在等待期间不解锁互斥元，把数据压入队列的线程就无法锁定这个互斥元，
        // 就无法压入数据，就无法执行notify_one()，所以等待的线程就永远处于等待状态
        std::unique_lock<std::mutex> lk(mut);//-------------------④
        std::cout << "before wait" << std::endl;
        //判断队列中是否有数据，如果没有继续阻塞等待被唤醒，如果有数据的话，也会锁定互斥单元，并执行wait后面的代码  等待的时候必须要解锁互斥元，上面才能发送notify_one()
        data_cond.wait(lk, []{return !data_queue.empty();});//-------------------⑤
        std::cout << "after  wait" << std::endl;
        int data = data_queue.front();
        std::cout << data << std::endl;
        data_queue.pop();
        lk.unlock();//-------------------⑥
        //假设处理数据data的函数process要花费大量时间，所以提前解锁
        //process(data);
    }
}
int main(){
    std::thread t1(data_preparation_thread);
    std::thread t2(data_process_thread);
    t1.join();
    t2.join();
}